﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace MCSharpLib.MNet
{
    public class TCPServer
    {
        private Dictionary<int, Socket> dct_servers = new Dictionary<int, Socket>();
        private Dictionary<string, Socket> dct_clients = new Dictionary<string, Socket>();
        private Dictionary<int, Thread> dct_Thread_server = new Dictionary<int, Thread>();
        private Dictionary<string, Thread> dct_Thread_client = new Dictionary<string, Thread>();
        public delegate void DataMethod(object data,string ip);
        public DataMethod DataReceive
        {
            get;
            set;
        }
        public int BufferSize
        {
            get;
            set;
        }
        public Dictionary<int, Socket> Sockets
        {
            get
            {
                return dct_servers;
            }
        }
        public string IP
        {
            get;
            set;
        }
        public void ListenTo(int port)
        {
            if (dct_servers.ContainsKey(port))
                return;
            try
            {
                Socket sck_new = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sck_new.Bind(new IPEndPoint(IPAddress.Parse(IP), port));
                sck_new.Listen(10);
                Thread thr = new Thread(WaitFor);
                thr.IsBackground = true;
                thr.Start(sck_new);
                dct_servers.Add(port, sck_new);
                dct_Thread_server.Add(port, thr);

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        private void WaitFor(object socket_listen)
        {
            while (true)
            {
                Socket sokConnection = null;
                try
                {
                    sokConnection = ((Socket)socket_listen).Accept();
                    dct_clients.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);
                    Thread thr = new Thread(GetData);
                    thr.IsBackground = true;
                    thr.Start(sokConnection);
                    dct_Thread_client.Add(sokConnection.RemoteEndPoint.ToString(), thr);
                }
                catch (SocketException ex)
                {
                    if(sokConnection != null)
                        DisconnectClient(sokConnection.RemoteEndPoint.ToString());
                }
            }  
        }
        private void GetData(object socket)
        {
            try
            {
                while (true)
                {
                    byte[] b_buffer = new byte[BufferSize];
                    int i_len = ((Socket)socket).Receive(b_buffer);
                    byte[] b_bufer_real = new byte[i_len];
                    Array.Copy(b_buffer, b_bufer_real, i_len);
                    DataReceive(b_bufer_real, ((Socket)socket).RemoteEndPoint.ToString());
                }
            }
            catch (SocketException ex)
            {
                if (socket != null)
                    DisconnectClient(((Socket)socket).RemoteEndPoint.ToString());
            }
        }
        public void DisconnectClient(string ip)
        {
            if (dct_clients.ContainsKey(ip))
            {
                if (dct_Thread_client.ContainsKey(ip))
                {
                    dct_Thread_client[ip].Abort();
                    dct_Thread_client.Remove(ip);
                }
                dct_clients[ip].Disconnect(false);
                dct_clients.Remove(ip);

            }
        }
        public void StopListen(int port)
        {
            if (dct_servers.ContainsKey(port))
            {
                if (dct_Thread_server.ContainsKey(port))
                {
                    dct_Thread_server[port].Abort();
                    dct_Thread_server.Remove(port);
                }
                dct_servers[port].Disconnect(false);
                dct_servers.Remove(port);

            }
        }
    }
    public class TCPClient
    {
        private Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        private Thread thread;
        public delegate void DataMethod(object data);
        public DataMethod DataReceive { get; set; }
        public string IP
        {
            get;
            set;
        }
        public int BufferSize
        {
            get;
            set;
        }
        public void ConnectTo(int port)
        {
            socket.Connect(new IPEndPoint(IPAddress.Parse(IP), port));
            thread = new Thread(WaitFor);
            thread.IsBackground = true;
            thread.Start();
        }
        private void WaitFor()
        {
            while (true)
            {
                try
                {
                    byte[] b_buffer = new byte[BufferSize];
                    int i_len = ((Socket)socket).Receive(b_buffer);
                    byte[] b_bufer_real = new byte[i_len];
                    Array.Copy(b_buffer, b_bufer_real, i_len);
                    DataReceive(b_bufer_real);
                }
                catch (SocketException ex)
                {
                    CloseConnection();
                }
            }
        }
        public void SendData(byte[] data)
        {
            socket.Send(data);
        }
        public void CloseConnection()
        {
            thread.Abort();
            socket.Close();
            
        }
        public void Dispose()
        {
            CloseConnection();
        }
    }
}
